/*
 * Steps.cpp
 *
 *  Created on: Dec 9, 2011
 *      Author: qzhang
 */

#include "Steps.h"
#include <cmath>
#include "frame.h"
#include "spriteFactory.h"
#include "multiSpriteFactory.h"
#include "sprite.h"
#include "viewport.h"
#include "HorizontalMovingStep.h"
#include "VerticalMovingStep.h"
#include "UnregularSprite.h"
#include "SpringSprite.h"

Steps::Steps(DoodleSprite* doodleSprite) :
	gameData(Gamedata::getInstance()),
	doodle(doodleSprite),
	screen1(NULL),
	screen2(NULL),
	screen1Coord(0.0, 0.0),
	screen2Coord(0.0, -gameData->getXmlFloat("screenHeight")),
	collisionStrategy(new RectangularCollisionStrategy()),
	screenNum(1)
{
	cout<<"Initialize screen1Coord"<<screen1Coord<<endl;
	cout<<"Initiliaze screen2Coord"<<screen2Coord<<endl;

	screen1 = makeSteps(gameData->getXmlFloat("viewHeight"), 0);
	//Viewport::getInstance()->setCurrentScreen(screen1Coord);
}

Steps::~Steps() {
	//delete steps in screen1 and screen2

	if (NULL != screen1) {
		for (vector<Sprite*>::const_iterator iter = screen1->begin();
				iter != screen1->end(); iter++) {
			delete (*iter);
		}

		delete screen1;
	}
	if (NULL != screen2) {
		for (vector<Sprite*>::const_iterator iter = screen2->begin();
				iter != screen2->end(); iter++) {
			delete (*iter);
		}

		delete screen2;
	}
}

//All y coordinates are negative after first screen
void Steps::update(const int& ticks)  {


	static bool flag = true;
	if (Viewport::getInstance()->Y() < screen1Coord[1] && flag) {
		screen2 = makeSteps(screen1Coord[1], screen2Coord[1]);
		flag = false;
		//cout<<"Generate Screen2 "<<Viewport::getInstance()->Y()<<" "<<screen1Coord[1]<<endl;
	}

	if (Viewport::getInstance()->Y() + gameData->getXmlFloat("viewHeight") < screen1Coord[1] ) {
		cout<<"delete screen1 "<<Viewport::getInstance()->Y()<<" "<<screen1Coord[1]<<endl;
		//delete steps in screen1
		if (NULL != screen1) {
			for (vector<Sprite*>::const_iterator iter = screen1->begin();
					iter != screen1->end(); iter++) {
				delete (*iter);
			}
            cout << screenNum++ << endl;

			delete screen1;
		}

		screen1 = screen2;
		screen2 = NULL;

		//change screen1Coord and screen2Coord
		screen1Coord = screen2Coord;

		screen2Coord[0] = 0;
		screen2Coord[1] = screen2Coord[1] - gameData->getXmlFloat("viewHeight");

		//flag for not regenerating screen2
		flag = true;
	}

	if (screen1 != NULL) {
		for (vector<Sprite*>::const_iterator iter = screen1->begin();
				iter != screen1->end(); iter++) {
			(*iter)->update(ticks);
		}
	}

	if (screen2 != NULL) {
		for (vector<Sprite*>::const_iterator iter = screen2->begin();
				iter != screen2->end(); iter++) {
			(*iter)->update(ticks);
		}
	}

	manageCollisions(ticks);

}

void Steps::draw() const {
	if (NULL != screen1) {
		for (vector<Sprite*>::const_iterator iter = screen1->begin();
				iter != screen1->end(); iter++) {
			(*iter)->draw();
		}

	}
	if (NULL != screen2) {
		for (vector<Sprite*>::const_iterator iter = screen2->begin();
				iter != screen2->end(); iter++) {
		 (*iter)->draw();
		}
	}
}

Sprite* Steps::makeSpring( const Vector2f & p, const float& stepWidth, const float& springWidth, const float& springHeight)
{
    Vector2f springPos(p[0] + stepWidth / 2.0 - springWidth / 2.0, p[1] - springHeight + 1);
    Vector2f springVel(gameData->getXmlFloat("springXspeed"), gameData->getXmlFloat("springYspeed"));
    Frame *springFrame = MultiSpriteFrameFactory::getInstance()->getUnregularFrame("spring", "spring");
    Sprite *springSprite = new SpringSprite(springPos, springVel, springFrame, "spring");
    return springSprite;
}

vector<Sprite*>* Steps::makeSteps(const float y1, const float y2) {
	cout<<"Make step for "<<y1<<"->"<<y2<<endl;
    if (screenNum > 80) {
        screenNum = 80;
    }
    while (screenNum <= 80) {
        int steps = abs((y2) - (y1)) / (40 + screenNum);
        Frame* frame = NULL;
        vector<Sprite*>* vec = new vector<Sprite*>;

	//Here you can generate steps whatever you like
        for (int i = 0; i < steps; i++) {

        	//generate green stable step
			if (i % 6 == 0) {
				frame = SpriteFrameFactory::getInstance()->getFrame(
						"stepHorizontal", "stepHorizontal");
				Vector2f p(
						rand()
								% (gameData->getXmlInt("viewWidth")
										- gameData->getXmlInt(
												"stepHorizontalWidth")),
						y1 - i * (40 + screenNum));

				Vector2f v(gameData->getXmlFloat("stepHorizontalXspeed"), gameData->getXmlFloat("stepHorizontalYspeed"));
				Sprite* stepSprite = new HorizontalMovingStep(p, v, frame);

				vec->push_back(stepSprite);
			} else if (i % 7 == 0) {
				//generate vertical moving step

				frame = SpriteFrameFactory::getInstance()->getFrame("stepVertical",
						"stepVertical");
				Vector2f p(
						rand()
								% (gameData->getXmlInt("viewWidth")
										- gameData->getXmlInt("stepVerticalWidth")),
						y1 - i * (40 + screenNum));
				Vector2f v(gameData->getXmlFloat("stepVerticalXspeed"), gameData->getXmlFloat("stepVerticalYspeed"));
				Sprite* stepSprite = new VerticalMovingStep(p, v, frame);
				vec->push_back(stepSprite);
			} else if (i % 8 == 0) {
				//generate horizontal moving step

				frame = MultiSpriteFrameFactory::getInstance()->getUnregularFrame("brokenStep", "brokenStep");
				Vector2f p(
						rand()
								% (gameData->getXmlInt("viewWidth")
										- gameData->getXmlInt(
												"brokenStep1Width")),
						y1 - i * (40 + screenNum));
				Vector2f v(gameData->getXmlFloat("brokenStepXspeed"),
						gameData->getXmlFloat("brokenStepYspeed"));
				Sprite* stepSprite = new UnregularSprite(p, v, frame, "brokenStep");
				vec->push_back(stepSprite);
			} else {
				frame = SpriteFrameFactory::getInstance()->getFrame("step",
						"step");
				Vector2f p(
						rand()
								% (gameData->getXmlInt("viewWidth")
										- gameData->getXmlInt("stepWidth")),
						y1 - i * (40 + screenNum));
				Vector2f v(0, 0);
				Sprite* stepSprite = new Sprite(p, v, frame);
				vec->push_back(stepSprite);

				//make possible spring
				if (rand() % 5 == 0) {
					Sprite* springSprite = makeSpring(p, gameData->getXmlFloat("stepWidth"), gameData->getXmlFloat("spring1Width"), gameData->getXmlFloat("spring1Height"));
					vec->push_back(springSprite);
				}
			}
		}


        return vec;
    }
}

void Steps::manageCollisions(const int& ticks) {
	if (doodle->velocityY() >= 0) {
		if (screen1 != NULL) {
			for (vector<Sprite*>::const_iterator iter = screen1->begin();
					iter != screen1->end(); iter++) {
				if (doodle->getHighestPosition()[1] + doodle->getFrame()->getHeight() <= (*iter)->Y()) {
					if (collisionStrategy->execute(*doodle, **iter)) {
						if ((*iter)->collide(doodle)) doodle->jump();
						return;
					}
				}
			}
		}

		if (screen2 != NULL) {
			for (vector<Sprite*>::const_iterator iter = screen2->begin();
					iter != screen2->end(); iter++) {
				if (doodle->getHighestPosition()[1] + doodle->getFrame()->getHeight() <= (*iter)->Y()) {
					if (collisionStrategy->execute(*doodle, **iter)) {
						if ((*iter)->collide(doodle)) doodle->jump();
						return;
					}
				}
			}
		}
	}
}
